﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static NIDViewer.NidParser;

namespace NIDViewer
{
    public class NidParser
    {
        private readonly byte[] _data;

        public NidParser(byte[] data)
        {
            _data = data;
        }

        public class NidMatrix
        {
            public int Width;
            public int Height;
            public double[] Data = new double[0];
            public long Offset;
        }

        public class NidLine
        {
            public NidPoint[] Points = new NidPoint[0];
        }

        public class NidPoint
        {
            public double X, Y;
            public NidPoint() { }

            public NidPoint(double x, double y)
            {
                X = x;
                Y = y;
            }
        }

        public NidFileData GetAllChannelMatrixData()
        {
            var result = new NidFileData();
            string text = Encoding.ASCII.GetString(_data);
            return ParseBinaryNidChannels(text);
        }

        public NidChannelData GetMatrixData(DataChannelTypes channel)
        {
            var nidData = GetAllChannelMatrixData();
            var channelData = nidData.Channels[(int)channel];
            channelData.MeasureWidth= nidData.MeasureWidth;
            channelData.MeasureHeight= nidData.MeasureHeight;
            channelData.Lines = nidData.Lines;
            channelData.Points = nidData.Points;
            return channelData;
        }

        private NidFileData ParseBinaryNidChannels(string text)
        {
            var result = new NidFileData();

            try
            {
                // 解析头部信息
                var header = new ConfigParser();
                string dataHeaderPart = text.Split(new[] { "#!" }, StringSplitOptions.None)[0];
                header.ReadString(dataHeaderPart);

                // 提取Group和Channel信息
                var groupNames = new List<string>();
                var dataSet = new List<string>();
                var ds = "DataSet";

                if (header.ContainsKey(ds) && header[ds].ContainsKey("GroupCount"))
                {
                    var grCnt = int.Parse(header[ds]["GroupCount"]);
                    for (var gr = 0; gr < grCnt; gr++)
                    {
                        if (header[ds].ContainsKey($"Gr{gr}-Name"))
                        {
                            groupNames.Add(header[ds][$"Gr{gr}-Name"]);
                        }
                        var gc = int.Parse(header[ds][$"Gr{gr}-Count"]);
                        for (var g = 0; g < gc; g++)
                        {
                            var grKey = $"Gr{gr}-Ch{g}";
                            if (header[ds].ContainsKey(grKey))
                            {
                                dataSet.Add(header[ds][grKey]);
                            }
                        }
                    }
                }

                // 提取数据参数
                var parm = new Dictionary<string, List<object>>();
                var terms = new List<string> { "Frame", "Points", "Lines", "SaveBits", "Dim0Min", "Dim0Range", "Dim0Unit", "Dim1Min", "Dim1Range", "Dim1Unit", "Dim2Min", "Dim2Range", "Dim2Unit", "Dim2Name" };
                var types = new List<int> { 0, 1, 1, 1, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0 };

                // 提取LinePoints信息
                var dataPoints = new List<List<int>>();
                foreach (var data in dataSet)
                {
                    if (header.ContainsKey(data))
                    {
                        var h = header[data];
                        var linePoints = new List<int>();
                        if (h.ContainsKey("LineDim0Min"))
                        {
                            foreach (var dic in h)
                            {
                                if (System.Text.RegularExpressions.Regex.IsMatch(dic.Key, @"^LineDim\d*Points$"))
                                {
                                    linePoints.Add(int.Parse(dic.Value));
                                }
                            }
                        }
                        dataPoints.Add(linePoints);
                    }
                }
                parm["LinePoints"] = dataPoints.ConvertAll(x => x as object);

                List<Func<object, object>> typ = new()
                {
                    x => x != null ? x.ToString() : "",   // 转换为字符串  
                    x => Convert.ToInt32(x),   // 转换为整数  
                    x => Convert.ToDouble(x)    // 转换为浮点数  
                };

                for (var i = 0; i < terms.Count; i++)
                {
                    var term = terms[i];
                    foreach (var data in dataSet)
                    {
                        if (header.ContainsKey(data))
                        {
                            var h = header[data];
                            if (h.ContainsKey(term))
                            {
                                if (!parm.ContainsKey(term))
                                {
                                    parm.Add(term, new List<object>());
                                }
                                parm[term].Add(typ[types[i]](h[term]));
                            }
                        }
                    }
                }

                // 读取二进制数据
                if (parm.ContainsKey("Points") && parm.ContainsKey("Lines") && parm.ContainsKey("SaveBits"))
                {
                    var channelDataList = ReadBinaryDataFromFile(parm, dataSet);

                    // 按Frame类型分类数据
                    var categorizedChannels = CategorizeChannelsByFrame(channelDataList, parm);
                    result.Channels.AddRange(categorizedChannels);

                    // 为NidFileData赋值Points、Lines、Width、Height属性
                    if (parm["Points"].Count > 0 && parm["Lines"].Count > 0)
                    {
                        // 使用第一个通道的Points和Lines作为文件级别的值
                        result.Points = Convert.ToInt32(parm["Points"][0]);
                        result.Lines = Convert.ToInt32(parm["Lines"][0]);
                        
                        // 计算Width和Height（基于Dim0Range和Dim1Range）
                        if (parm.ContainsKey("Dim0Range") && parm.ContainsKey("Dim1Range") && 
                            parm["Dim0Range"].Count > 0 && parm["Dim1Range"].Count > 0)
                        {
                            result.MeasureWidth = Convert.ToDouble(parm["Dim0Range"][0]);
                            result.MeasureHeight = Convert.ToDouble(parm["Dim1Range"][0]);
                        }
                        else
                        {
                            // 如果没有Dim0Range和Dim1Range，使用默认值
                            result.MeasureWidth = result.Points;
                            result.MeasureHeight = result.Lines;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // 如果解析失败，返回空结果
                System.Diagnostics.Debug.WriteLine($"ParseBinaryNidChannels error: {ex.Message}");
            }

            return result;
        }

        private List<NidChannelData> ReadBinaryDataFromFile(Dictionary<string, List<object>> parm, List<string> dataSet)
        {
            var channelDataList = new List<NidChannelData>();
            try
            {
                // 计算所需的数据大小
                var requiredSize = 0;
                List<int> points = parm["Points"].Select(x => Convert.ToInt32(x)).ToList();
                List<int> lines = parm["Lines"].Select(x => Convert.ToInt32(x)).ToList();
                List<int> saveBits = parm["SaveBits"].Select(x => Convert.ToInt32(x)).ToList();

                for (int i = 0; i < points.Count; i++)
                {
                    requiredSize += (points[i] * lines[i] * saveBits[i]) / 8;
                }

                // 从文件末尾读取二进制数据
                int dataStartOffset = _data.Length - requiredSize;
                if (dataStartOffset < 0) return channelDataList;

                // 读取原始字节数据
                byte[] binaryData = new byte[requiredSize];
                Array.Copy(_data, dataStartOffset, binaryData, 0, requiredSize);

                // 根据SaveBits确定数据类型
                Type dataType = saveBits.Count > 0 ? saveBits[0] switch
                {
                    16 => typeof(short),
                    32 => typeof(int),
                    _ => typeof(int)
                } : typeof(int);

                // 转换字节数据为数值数组
                var dataArray = ConvertBytesToArray(binaryData, dataType);

                // 计算累积和以分割数据
                int[] cumulativeSum = new int[points.Count];
                cumulativeSum[0] = points[0] * lines[0];
                for (int i = 1; i < points.Count; i++)
                {
                    cumulativeSum[i] = cumulativeSum[i - 1] + points[i] * lines[i];
                }

                // 分割数据并创建矩阵
                int startIndex = 0;
                int processCount = points.Count - 1;
                for (int i = 0; i < processCount; i++)
                {
                    int length = (i == 0) ? cumulativeSum[i] : cumulativeSum[i] - cumulativeSum[i - 1];
                    var channelData = new NidChannelData();

                    // 获取channel名称
                    if (i < dataSet.Count)
                    {
                        channelData.ChannelName = GenerateChannelName(dataSet[i], i);
                    }
                    else
                    {
                        channelData.ChannelName = $"Channel_{i}";
                    }

                    // 创建矩阵数据
                    var matrixData = new double[length];
                    for (int j = 0; j < length; j++)
                    {
                        if (startIndex + j < dataArray.Length)
                        {
                            try
                            {
                                var q = Math.Pow(2, i < saveBits.Count ? saveBits[i] : 32);
                                var z0 = q / 2;
                                var rawValue = dataArray.GetValue(startIndex + j);
                                var scaledValue = (Convert.ToDouble(rawValue) + z0) / q;

                                if (parm.ContainsKey("Dim2Range") && parm.ContainsKey("Dim2Min") &&
                                    i < parm["Dim2Range"].Count && i < parm["Dim2Min"].Count)
                                {
                                    var zRange = Convert.ToDouble(parm["Dim2Range"][i]);
                                    var zMin = Convert.ToDouble(parm["Dim2Min"][i]);
                                    scaledValue = scaledValue * zRange + zRange;
                                }

                                matrixData[j] = (double)scaledValue;
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine($"Error processing matrix data at index {j}: {ex.Message}");
                                matrixData[j] = 0.0f; // 设置默认值
                            }
                        }
                    }

                    // 应用LinePoints裁剪（如果存在）
                    double[] finalMatrixData = matrixData;
                    if (parm.ContainsKey("LinePoints") && i < parm["LinePoints"].Count)
                    {
                        var linePoints = parm["LinePoints"][i] as List<int>;
                        if (linePoints != null && linePoints.Count > 0)
                        {
                            // 重塑数据为矩阵格式
                            var reshapedData = ReshapeData(matrixData, points[i], lines[i]);

                            // 应用LinePoints裁剪
                            var croppedData = ApplyLinePointsCrop(reshapedData, linePoints);
                            finalMatrixData = croppedData;
                        }
                    }

                    // 重塑数据为矩阵格式
                    var matrix = new NidMatrix
                    {
                        Width = points[i],
                        Height = lines[i],
                        Data = finalMatrixData,
                        Offset = dataStartOffset + startIndex * (saveBits[i] / 8)
                    };

                    // 添加调试信息
                    System.Diagnostics.Debug.WriteLine($"Channel {i}: {channelData.ChannelName}, Points: {points[i]}, Lines: {lines[i]}, DataLength: {finalMatrixData.Length}");
                    if (finalMatrixData.Length > 0)
                    {
                        System.Diagnostics.Debug.WriteLine($"  First few values: {finalMatrixData[0]}, {finalMatrixData[1]}, {finalMatrixData[2]}");
                        System.Diagnostics.Debug.WriteLine($"  Min: {finalMatrixData.Min()}, Max: {finalMatrixData.Max()}");
                    }

                    channelData.Matrix = matrix;

                    // 生成Lines和Points数据
                    GenerateChannelLinesAndPoints(channelData, points[i], lines[i], i);

                    channelDataList.Add(channelData);

                    startIndex += length;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"ReadBinaryDataFromFile error: {ex.Message}");
            }

            return channelDataList;
        }

        private Array ConvertBytesToArray(byte[] bytes, Type dataType)
        {
            int elementSize = System.Runtime.InteropServices.Marshal.SizeOf(dataType);
            int elementCount = bytes.Length / elementSize;
            Array array = Array.CreateInstance(dataType, elementCount);
            Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length);
            return array;
        }

        private string GenerateChannelName(string dataSetName, int index)
        {
            // 根据数据集名称生成友好的channel名称
            if (dataSetName.Contains("Gr0-Ch0")) return "Amplitude forward";
            if (dataSetName.Contains("Gr0-Ch1")) return "Z-Axis forward";
            if (dataSetName.Contains("Gr0-Ch3")) return "Phase forward";
            if (dataSetName.Contains("Gr0-Ch7")) return "Z-Axis Sensor forward";
            if (dataSetName.Contains("Gr1-Ch0")) return "Amplitude backward";
            if (dataSetName.Contains("Gr1-Ch1")) return "Z-Axis backward";
            if (dataSetName.Contains("Gr1-Ch3")) return "Phase backward";
            if (dataSetName.Contains("Gr1-Ch7")) return "Z-Axis Sensor backward";

            return $"Channel_{index}";
        }

        private double[,] ReshapeData(double[] data, int width, int height)
        {
            var reshaped = new double[height, width];
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    int index = y * width + x;
                    if (index < data.Length)
                    {
                        reshaped[y, x] = data[index];
                    }
                }
            }
            return reshaped;
        }

        private double[] ApplyLinePointsCrop(double[,] data, List<int> linePoints)
        {
            var croppedData = new List<double>();

            for (int y = 0; y < data.GetLength(0) && y < linePoints.Count; y++)
            {
                int pointsToTake = linePoints[y];
                for (int x = 0; x < pointsToTake && x < data.GetLength(1); x++)
                {
                    croppedData.Add(data[y, x]);
                }
            }

            return croppedData.ToArray();
        }

        private List<NidChannelData> CategorizeChannelsByFrame(List<NidChannelData> channelDataList, Dictionary<string, List<object>> parm)
        {
            var categorizedChannels = new List<NidChannelData>();

            if (!parm.ContainsKey("Frame") || !parm.ContainsKey("Dim2Name"))
            {
                return channelDataList; // 如果没有Frame信息，直接返回原始数据
            }

            var dataNames = new List<string> { "Spec forward", "Spec backward", "Spec fwd pause", "Spec bwd pause", "Scan forward", "Scan backward", "2nd scan forward", "2nd scan backward", "Frequency sweep", "Frequency sweep SHO", "Spectrum FFT", "Spectrum Fit" };
            var dataTypes = new List<int> { 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2 };

            // 查找框架索引
            List<int> validIndices = new List<int>();
            for (int i = 0; i < parm["Frame"].Count; i++)
            {
                if (dataNames.Contains(parm["Frame"][i].ToString()))
                {
                    validIndices.Add(i);
                }
            }

            // 只处理有效的数据类型
            for (int i = 0; i < validIndices.Count && i < channelDataList.Count; i++)
            {
                int frameIndex = validIndices[i];
                var channelData = channelDataList[i];

                // 根据Frame类型和Dim2Name更新channel名称
                string frameType = parm["Frame"][frameIndex].ToString();
                string dim2Name = frameIndex < parm["Dim2Name"].Count ? parm["Dim2Name"][frameIndex].ToString() : "";

                // 生成更详细的channel名称
                channelData.ChannelName = GenerateDetailedChannelName(frameType, dim2Name, frameIndex);

                // 添加调试信息，显示frameIndex
                System.Diagnostics.Debug.WriteLine($"Processing frame {frameIndex}: {frameType} - {dim2Name}");

                categorizedChannels.Add(channelData);
            }

            return categorizedChannels;
        }

        private string GenerateDetailedChannelName(string frameType, string dim2Name, int index)
        {
            // 根据Frame类型和Dim2Name生成详细的channel名称
            string baseName = frameType switch
            {
                "Scan forward" => "Forward Scan",
                "Scan backward" => "Backward Scan",
                "2nd scan forward" => "2nd Forward Scan",
                "2nd scan backward" => "2nd Backward Scan",
                "Spec forward" => "Forward Spec",
                "Spec backward" => "Backward Spec",
                "Spec fwd pause" => "Forward Spec Pause",
                "Spec bwd pause" => "Backward Spec Pause",
                "Frequency sweep" => "Frequency Sweep",
                "Frequency sweep SHO" => "Frequency Sweep SHO",
                "Spectrum FFT" => "Spectrum FFT",
                "Spectrum Fit" => "Spectrum Fit",
                _ => $"Frame_{index}"
            };

            if (!string.IsNullOrEmpty(dim2Name))
            {
                return $"{baseName} - {dim2Name}";
            }

            return baseName;
        }

        private void GenerateChannelLinesAndPoints(NidChannelData channelData, int width, int height, int channelIndex)
        {
            // 从Matrix中提取数据并拆分成行数据集
            if (channelData.Matrix != null && channelData.Matrix.Data != null)
            {
                var matrix = channelData.Matrix;
                var matrixData = matrix.Data;
                
                // 按照Lines拆分成行数据集
                for (int lineIndex = 0; lineIndex < height; lineIndex++)
                {
                    var linePoints = new List<NidPoint>();
                    
                    // 为每一行提取对应的点数据
                for (int x = 0; x < width; x++)
                {
                        int dataIndex = lineIndex * width + x;
                        if (dataIndex < matrixData.Length)
                        {
                            // 使用X坐标和矩阵数据值创建点
                            linePoints.Add(new NidPoint(x, matrixData[dataIndex]));
                        }
                    }
                    
                    channelData.LineData.Add(linePoints);
                }
            }
        }

        private int GetChannelIndex(string channelName)
        {
            // 根据channel名称返回索引
            if (channelName.Contains("Amplitude forward") || channelName.Contains("Gr0-Ch0")) return 0;
            if (channelName.Contains("Z-Axis forward") || channelName.Contains("Gr0-Ch1")) return 1;
            if (channelName.Contains("Phase forward") || channelName.Contains("Gr0-Ch3")) return 2;
            if (channelName.Contains("Z-Axis Sensor forward") || channelName.Contains("Gr0-Ch7")) return 3;
            if (channelName.Contains("Amplitude backward") || channelName.Contains("Gr1-Ch0")) return 4;
            if (channelName.Contains("Z-Axis backward") || channelName.Contains("Gr1-Ch1")) return 5;
            if (channelName.Contains("Phase backward") || channelName.Contains("Gr1-Ch3")) return 6;
            if (channelName.Contains("Z-Axis Sensor backward") || channelName.Contains("Gr1-Ch7")) return 7;
            return 0; // 默认返回0
        }
    }

    public class NidChannelData
    {
        public string ChannelName { get; set; } = string.Empty;

        public NidMatrix Matrix { get; set; } = new NidMatrix();

        public List<List<NidPoint>> LineData { get; set; } = new List<List<NidPoint>>();

        public int Points { get; set; }

        public int Lines { get; set; }

        public double MeasureWidth { get; set; }

        public double MeasureHeight { get; set; }
    }

    public class NidFileData
    {
        public List<NidChannelData> Channels { get; set; } = new List<NidChannelData>();

        public int Points { get; set; }

        public int Lines { get; set; }

        public double MeasureWidth { get; set; }

        public double MeasureHeight { get; set; }
    }
}
